/**************************************************************************
 * @file usr_lcd.c
 * @author 黑马小乌龟 (532352406@qq.com)
 * @brief IC:         st7567
 * @version 0.1
 * @date 2025-08-15
 *
 * @copyright Copyright (c) 2025
 *
 *************************************************************************/
#include "main.h"
#include "usr_lcd_ascii_font.h"
#include "usr_lcd.h"

/****************************************************/
void writecommand(uint8_t cmd);  // 写命令
void writedata(uint8_t dataa);   // 写数据
// void writedata1(uint8_t dataa);  // 写数据
void disp_clear(void);
void disp_full(void);
void disp_col(void);
void disp_row(void);
void dispgraphiCS(void);  // dispgraphiCS
void dispstr(uint8_t d);  // 显示字符，0是第一行，1是第二行

#define delay(ms) SysTick_Delay(ms)

/*********************************************************************************************/
uint8_t *p_dis_start_line=0;
extern UsrMainDatT main_dat;

#define LCD_COLUMN_MAX 128u
#define LCD_ROW_MAX 8u

/*--  宽度x高度=128x64/8 = 1024Byte  --*/
static uint8_t dis_buf[LCD_COLUMN_MAX*LCD_ROW_MAX] = {0x00};

const ASCII_FONT_INFOR_T ascii_16x16_font={
    .font_width = 8u,
    .font_height = 16u,
    .p_font_table = ascii_16x16,
};

const ASCII_FONT_INFOR_T ascii_16x16_font_rev={
    .font_width = 8u,
    .font_height = 16u,
    .p_font_table = asscii_16x16_rev,
};
const ASCII_FONT_INFOR_T ascii_16x16_font_bold={
    .font_width = 8u,
    .font_height = 16u,
    .p_font_table = asscii_16x16_B,
};

const ASCII_FONT_INFOR_T ascii_32x32_font={
    .font_width = 16u,
    .font_height = 32u,
    .p_font_table = ascii_32x32,
};
const ASCII_FONT_INFOR_T ascii_24x24_font={
    .font_width = 12u,
    .font_height = 24u,
    .p_font_table = ascii_24x24,
};
/************************************************************************************/
void writecommand(uint8_t cmd) {
    // int i;
    while(SPI_GetStatus(SPI_UNIT,SPI_FLAG_IDLE) == RESET);
    LCD_A0_CTL(0);
    SPI_Trans(SPI_UNIT, &cmd, 1, 1000);
}

void writedata(uint8_t dat) {
    // int i;
    while(SPI_GetStatus(SPI_UNIT,SPI_FLAG_IDLE) == RESET);
    LCD_A0_CTL(1);
    SPI_Trans(SPI_UNIT, &dat, 1, 1000);
}

void lcd_ascii_str_dis(uint8_t row, uint8_t column,const ASCII_FONT_INFOR_T font_infor, const char *p_str){
    uint16_t start_add;
    uint16_t font_index;
    uint8_t *p_dis_area;
    const char *tmp_str = p_str;
    uint8_t w=font_infor.font_width,row_num,str_cnt;
    int i,j;
    row_num = font_infor.font_height>>3;
    str_cnt = 0;
    while(tmp_str[str_cnt] != '\0'){
        
        font_index = (tmp_str[str_cnt] - ' ')*w*row_num;
        
        for(j=0;j<row_num;j++){
            start_add = (row+j)*LCD_COLUMN_MAX+(column+str_cnt*w);
            p_dis_area = &dis_buf[start_add];

            for(i=0;i<w;i++){
                *p_dis_area = font_infor.p_font_table[font_index++];
                p_dis_area++;
            }
        }
        str_cnt++;
    }
}

/****************************************************/

/****************************************************/
void lcd_init(void) {
    LCD_RES_CTL(1);
    delay(30);
    LCD_RES_CTL(0);
    delay(30);
    LCD_RES_CTL(1);
    delay(100);

    writecommand(0xE2);

    delay(10);

    writecommand(0xA2);  // 0xa2设置偏压比为1/9
    writecommand(0xA0);  // 0xA0设置列地址从00H开始
    writecommand(0xC8);  // 0xc8设置com扫描方向，从COM(n-1)到 COM0
    writecommand(0x23);  // vop粗调
    writecommand(0x81);  // vop双指令
    writecommand(0x32);  // vop微调
    writecommand(0x2F);  // 0x2f电源状态、输出缓冲开、内部电压调整开，电压调节开关
    writecommand(0xB0);  // 0xb0设置页列地址
    writecommand(0xAF);  // 0xaf设置显示LCD开关
    writecommand(0xA6);  // 0xa6设置正常显开关
}
/****************************************************/
void disp_clear(void) {  // 清屏

    uint8_t i, j;
    for (i = 0; i < 9; i++) {
        writecommand(0x00);
        writecommand(0xb0 + i);
        writecommand(0x00);
        writecommand(0x10);
        for (j = 0; j < 132; j++) writedata(0x00);
    }
}
/****************************************************/


void lcd_test_fun(void) {
    disp_clear();  // 清屏
}

static uint8_t lcd_dis_buf_line_cnt=0;

/**
 * @brief  LED Init
 * @param  None
 * @retval None
 */
static void LCD_GPIO_Init(void) {
    stc_gpio_init_t stcGpioInit;

    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_RST;
    stcGpioInit.u16PinDir = PIN_DIR_OUT;
    (void)GPIO_Init(LCD_RES_CTL_PORT, LCD_RES_CTL_PIN, &stcGpioInit);
    (void)GPIO_Init(LCD_A0_CTL_PORT, LCD_A0_CTL_PIN, &stcGpioInit);
}

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @brief  DMA transmit complete callback.
 * @param  None
 * @retval None
 */
static void DMA_TransCompleteCallback(void) {

    // enTxCompleteFlag = SET;
    // DDL_Printf("DMA-INT\n");

    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_TX_INT_CH);
    DMA_ChCmd(DMA_UNIT, DMA_TX_CH, DISABLE);

    lcd_dis_buf_line_cnt++;
    lcd_dis_buf_line_cnt %= LCD_MAX_BUF_LINE;

    p_dis_start_line = &dis_buf[lcd_dis_buf_line_cnt*LCD_ONE_LINE_MAX_BYTE];
    if(lcd_dis_buf_line_cnt == 0){
        main_dat.lcd_flush_cnt = 300u;
        main_dat.lcd_flush_active = 0;
    }else{
        main_dat.lcd_flush_active = 1;
    }
    
}

/**
 * @brief  SPI configure.
 * @param  None
 * @retval None
 */
void LCD_SPI_Config(void) {
    stc_spi_init_t stcSpiInit;
    stc_dma_init_t stcDmaInit;
    stc_irq_signin_config_t stcIrqSignConfig;
    stc_gpio_init_t stcGpioInit;

    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinDrv = PIN_HIGH_DRV;
    stcGpioInit.u16PinInputType = PIN_IN_TYPE_CMOS;
    (void)GPIO_Init(SPI_SS_PORT, SPI_SS_PIN, &stcGpioInit);
    (void)GPIO_Init(SPI_SCK_PORT, SPI_SCK_PIN, &stcGpioInit);
    (void)GPIO_Init(SPI_MOSI_PORT, SPI_MOSI_PIN, &stcGpioInit);

    /* Configure Port */
    GPIO_SetFunc(SPI_SS_PORT, SPI_SS_PIN, SPI_SS_FUNC);
    GPIO_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC);
    GPIO_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC);

    LCD_GPIO_Init();

    /* Configuration SPI */
    FCG_Fcg1PeriphClockCmd(SPI_CLK, ENABLE);
    SPI_StructInit(&stcSpiInit);
    stcSpiInit.u32WireMode = SPI_4_WIRE;
    stcSpiInit.u32TransMode = SPI_SEND_ONLY;
    stcSpiInit.u32MasterSlave = EXAMPLE_SPI_MASTER_SLAVE;
    stcSpiInit.u32Parity = SPI_PARITY_INVD;
    stcSpiInit.u32SpiMode = SPI_MD_3;
    stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV2;
    stcSpiInit.u32DataBits = SPI_DATA_SIZE_8BIT;
    stcSpiInit.u32FirstBit = SPI_FIRST_MSB;
    stcSpiInit.u32FrameLevel = SPI_1_FRAME;
    (void)SPI_Init(SPI_UNIT, &stcSpiInit);

    /* DMA configuration */
    FCG_Fcg0PeriphClockCmd(DMA_CLK, ENABLE);
    (void)DMA_StructInit(&stcDmaInit);
    stcDmaInit.u32IntEn = DMA_INT_ENABLE;
    stcDmaInit.u32BlockSize = 1UL;
    stcDmaInit.u32TransCount = EXAMPLE_SPI_BUF_LEN;
    stcDmaInit.u32DataWidth = DMA_DATAWIDTH_8BIT;
    /* Configure TX */
    stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
    stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
    stcDmaInit.u32SrcAddr = (uint32_t)(&dis_buf[0]);
    stcDmaInit.u32DestAddr = (uint32_t)(&SPI_UNIT->DR);
    if (LL_OK != DMA_Init(DMA_UNIT, DMA_TX_CH, &stcDmaInit)) {
        for (;;) {
        }
    }
    AOS_SetTriggerEventSrc(DMA_TX_TRIG_CH, SPI_TX_EVT_SRC);

    /* DMA receive NVIC configure */
    stcIrqSignConfig.enIntSrc = DMA_TX_INT_SRC;
    stcIrqSignConfig.enIRQn = DMA_TX_IRQ_NUM;
    stcIrqSignConfig.pfnCallback = &DMA_TransCompleteCallback;
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_TX_INT_CH);
    (void)INTC_IrqSignIn(&stcIrqSignConfig);
    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
    NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);


    // /* Enable DMA and channel */
    DMA_Cmd(DMA_UNIT, ENABLE);
    // DMA_ChCmd(DMA_UNIT, DMA_TX_CH, ENABLE);
    // DMA_ChCmd(DMA_UNIT, DMA_RX_CH, ENABLE);
    SPI_Cmd(SPI_UNIT, ENABLE);
}

/**
 * @brief  SPI configure.
 * @param  None
 * @retval None
 */
void DMA_spi_send_one_line_dat_start(uint8_t start_line_add, uint8_t *p_buf, uint16_t buf_len) {

    writecommand(0xb0 + start_line_add);
    writecommand(0x10);
    writecommand(0x00);

    DMA_SetSrcAddr(DMA_UNIT, DMA_TX_CH, (uint32_t)(&p_buf[1]));
    DMA_SetTransCount(DMA_UNIT, DMA_TX_CH, (buf_len-1));
    // DMA_SetSrcAddr(DMA_UNIT, DMA_TX_CH, (uint32_t)(&p_buf[0]));
    // DMA_SetTransCount(DMA_UNIT, DMA_TX_CH, (buf_len));
    DMA_ChCmd(DMA_UNIT, DMA_TX_CH, ENABLE);
    writedata(p_buf[0]);
}

void usr_lcd_flush_start(void) {
    lcd_dis_buf_line_cnt = 0;
    p_dis_start_line = &dis_buf[lcd_dis_buf_line_cnt * LCD_ONE_LINE_MAX_BYTE];
    main_dat.lcd_flush_cnt = 0;
    main_dat.lcd_flush_active = 0;
    DMA_spi_send_one_line_dat_start(lcd_dis_buf_line_cnt, p_dis_start_line, LCD_ONE_LINE_MAX_BYTE);
}

void usr_lcd_flush_next_line(void){
    DMA_spi_send_one_line_dat_start(lcd_dis_buf_line_cnt, p_dis_start_line, LCD_ONE_LINE_MAX_BYTE);
}
